using System.Collections.Concurrent;
using Serilog;
using Serilog.Core;
using Serilog.Sinks.SystemConsole.Themes;

namespace DiLu.Expansion.Serilog;

/// <summary>
///     Serilog日志
/// </summary>
public abstract class DoSerilog
{
    /// <summary>
    ///     线程安全的 Serilog日志集
    /// </summary>
    private static readonly ConcurrentDictionary<string, Lazy<Logger>> SerilogLogger = new();

    /// <summary>
    ///     获取Debug日志对象
    /// </summary>
    /// <returns>Serilog日志对象</returns>
    public static Logger GetDebugLogger()
    {
        var log = SerilogLogger.GetOrAdd("debug", _ =>
        {
            return new Lazy<Logger>(() =>
            {
                var logger = new LoggerConfiguration();
                logger.MinimumLevel.Debug();
                logger.WriteTo.Async(s =>
                    s.Logger(logConfig =>
                    {
                        logConfig.WriteTo
                            .Debug(outputTemplate: "[{Timestamp:yyyy-mm-dd HH:mm:ss.fffd}} {Level:u3}] {Message:lj}{NewLine}{Exception}");
                    }));
                return logger.CreateLogger();
            });
        });
        return log.Value;
    }

    /// <summary>
    ///     获取Console日志对象
    /// </summary>
    /// <returns>Serilog日志对象</returns>
    public static Logger GetConsoleLogger()
    {
        var log = SerilogLogger.GetOrAdd("console", _ =>
        {
            return new Lazy<Logger>(() =>
            {
                var logger = new LoggerConfiguration();
                logger.MinimumLevel.Debug();
                logger.WriteTo.Async(s =>
                    s.Logger(logConfig =>
                    {
                        logConfig.WriteTo.Console(theme: AnsiConsoleTheme.Sixteen,
                            outputTemplate: "[{Timestamp:yyyy-mm-dd HH:mm:ss.fffd} {Level:u3}] {Message:lj}{NewLine}{Exception}");
                    }));
                return logger.CreateLogger();
            });
        });
        return log.Value;
    }

    /// <summary>
    ///     获取文件日志对象
    /// </summary>
    /// <param name="folderName">文件夹名称</param>
    /// <returns>Serilog日志对象</returns>
    /// <exception cref="ArgumentNullException">文件夹名称不能为空</exception>
    /// <exception cref="ArgumentException">
    ///     文件夹名称不能出现的字符 : * ? " &lt; > |
    /// </exception>
    /// <example>
    ///     folder1-->logs/folder1/...<br />
    ///     folder1/folder2-->logs/folder1/folder2/...
    /// </example>
    public static Logger GetFileLogger(string folderName)
    {
        if (string.IsNullOrWhiteSpace(folderName))
            throw new ArgumentNullException(nameof(folderName));
        //判断文件夹名称不能出现的字符\ / : * ? " < > |
        if (folderName.Contains(':') || folderName.Contains('*') || folderName.Contains('?') || folderName.Contains('"') ||
            folderName.Contains('<') || folderName.Contains('>') || folderName.Contains('|'))
            throw new ArgumentException("""文件夹名称不能出现以下字符：\ / : * ? " < > |""");

        //组装文件夹名称
        string filePath;
        if (folderName.Contains('/') || folderName.Contains('\\'))
            filePath = Path.Combine(folderName.Split('/', '\\'));
        else
            filePath = folderName;

        filePath = Path.Combine($"{DateTime.Now:yyyy}", $"{DateTime.Now:MM}", $"{DateTime.Now:dd}", filePath);

        var log = SerilogLogger.GetOrAdd($"{filePath}", _ =>
        {
            return new Lazy<Logger>(() =>
            {
                //创建日志对象
                var logger = new LoggerConfiguration();
                logger.MinimumLevel.Debug();
                logger.WriteTo.Async(s => s.Logger(log =>
                {
                    var logFilePath = Path.Combine(AppContext.BaseDirectory, "logs", filePath, "log.txt");
                    log.WriteTo.File(logFilePath, rollingInterval: RollingInterval.Hour, rollOnFileSizeLimit: true);
                }));
                return logger.CreateLogger();
            });
        });

        return log.Value;
    }
}